package backtype.storm;

import java.util.Map;


/**
 * Provides functionality for validating configuration fields.
 */
public class ConfigValidation {

    /**
     * Declares methods for validating configuration values.
     */
    public static interface FieldValidator {
        /**
         * Validates the given field.
         * 
         * @param name
         *            the name of the field.
         * @param field
         *            The field to be validated.
         * @throws IllegalArgumentException
         *             if the field fails validation.
         */
        public void validateField(String name, Object field) throws IllegalArgumentException;
    }


    /**
     * Returns a new FieldValidator for a List of the given Class.
     * 
     * @param cls
     *            the Class of elements composing the list
     * @return a FieldValidator for a list of the given class
     */
    static FieldValidator FieldListValidatorFactory(final Class cls) {
        return new FieldValidator() {
            @Override
            public void validateField(String name, Object field) throws IllegalArgumentException {
                if (field == null) {
                    // A null value is acceptable.
                    return;
                }
                if (field instanceof Iterable) {
                    for (Object e : (Iterable) field) {
                        if (!cls.isInstance(e)) {
                            throw new IllegalArgumentException("Each element of the list " + name
                                    + " must be a " + cls.getName() + ".");
                        }
                    }
                    return;
                }
                throw new IllegalArgumentException("Field " + name + " must be an Iterable of "
                        + cls.getName());
            }
        };
    }

    /**
     * Validates a list of Numbers.
     */
    public static Object NumbersValidator = FieldListValidatorFactory(Number.class);

    /**
     * Validates is a list of Strings.
     */
    public static Object StringsValidator = FieldListValidatorFactory(String.class);

    /**
     * Validates is a list of Maps.
     */
    public static Object MapsValidator = FieldListValidatorFactory(Map.class);

    /**
     * Validates a power of 2.
     */
    public static Object PowerOf2Validator = new FieldValidator() {
        @Override
        public void validateField(String name, Object o) throws IllegalArgumentException {
            if (o == null) {
                // A null value is acceptable.
                return;
            }
            final long i;
            if (o instanceof Number && (i = ((Number) o).longValue()) == ((Number) o).doubleValue()) {
                // Test whether the integer is a power of 2.
                if (i > 0 && (i & (i - 1)) == 0) {
                    return;
                }
            }
            throw new IllegalArgumentException("Field " + name + " must be a power of 2.");
        }
    };
}
